package pl.edu.mimuw.irs.rcp.persistence.resource;

import java.io.InputStream;
import java.io.OutputStream;
import java.util.LinkedHashSet;
import java.util.Set;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import pl.edu.mimuw.irs.core.model.design.resource.Resource;
import pl.edu.mimuw.irs.core.model.design.resource.Resources;
import pl.edu.mimuw.irs.core.model.design.resource.Role;
import pl.edu.mimuw.irs.core.model.design.resource.RoleInstance;
import pl.edu.mimuw.irs.rcp.persistence.AbstractPersistence;
import pl.edu.mimuw.irs.rcp.persistence.resource.definition.ObjectFactory;
import pl.edu.mimuw.irs.rcp.persistence.resource.definition.ResourceType;
import pl.edu.mimuw.irs.rcp.persistence.resource.definition.ResourcesType;
import pl.edu.mimuw.irs.rcp.persistence.resource.definition.RoleType;


public class ResourcesPersistence extends AbstractPersistence<Resources> {

	public static final String HISTORY_FILE = "history.hst";
	public static final String DEFINITION_FILE = "resources.res";
	
	// *** Attributes
	
	// *** Methods

	@SuppressWarnings("unchecked")
	@Override
	public Resources loadFromStream(InputStream stream) throws Exception {
		JAXBContext context = JAXBContext.newInstance(ObjectFactory.class);
		Unmarshaller unmarshaller = context.createUnmarshaller();
		Object root = unmarshaller.unmarshal(stream);
		if (root == null) return null;// TODO : neat exception
		if (!(root instanceof JAXBElement<?>)) return null;
		JAXBElement<ResourcesType> resourcesElement = (JAXBElement<ResourcesType>) root;
		ResourcesType resources = resourcesElement.getValue();
		
		Resources result = loadResources(resources);
		
		return result;
	}
	
	protected Resources loadResources(ResourcesType resourcesType) {
		Resources resources = new Resources();
		
		for (ResourceType resourceType : resourcesType.getResource()) {
			Set<String> createdRoles = new LinkedHashSet<String>();
			Set<RoleInstance> roles = new LinkedHashSet<RoleInstance>();
			for (RoleType roleType : resourceType.getRole()) {
				if (createdRoles.contains(roleType.getName())) continue;
				Role role = new Role(roleType.getName());
				RoleInstance instance = new RoleInstance(role, roleType.getTimeModifier());
				createdRoles.add(roleType.getName());
				roles.add(instance);
			}
			
			Resource resource = new Resource(resourceType.getName(), roles);
			resource.setName(resourceType.getName());
			resource.setUnitCost(resourceType.getUnitCost());
			resources.add(resource);
		}
		
		return resources;
	}
	
	@Override
	public void writeToStream(Resources resources, OutputStream stream)
			throws Exception {
		JAXBContext context = JAXBContext.newInstance(ObjectFactory.class);
		Marshaller marshaller = context.createMarshaller();
		ResourcesType resourcesType = storeResources(resources);
		JAXBElement<ResourcesType> resourcesElement = new ObjectFactory().createResources(resourcesType);
		
		try {
			marshaller.marshal(resourcesElement, stream);
		} finally {
			if (stream != null) stream.close();
		}
	}

	private ResourcesType storeResources(Resources resources) {
		ResourcesType resourcesType = new ResourcesType();
		
		for (Resource resource : resources) {
			ResourceType resourceType = new ResourceType();
			for (RoleInstance instance : resource.getRolesMap().values()) {
				RoleType roleType = new RoleType();
				roleType.setName(instance.getRole().getName());
				roleType.setTimeModifier(instance.getModifier());
				resourceType.getRole().add(roleType);
			}
			resourceType.setName(resource.getName());
			resourceType.setUnitCost(resource.getUnitCost());
			resourcesType.getResource().add(resourceType);
		}
		
		return resourcesType;
	}

}
